﻿
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace MetroNextTools.NData
{
    /// <summary>
    /// 集合控件的数据集合存储类
    /// </summary>
    public class NCollection : Collection<object>,INotifyCollectionChanged,ICollectionChangedListener
    {
        #region Fields

        internal IEnumerable _itemsSource;
        private WeakCollectionChangedListener _collectionChangedListener;
        private bool _isBusy;

        #endregion

        #region Constructor

        public NCollection()
        {

        }

        #endregion
       
        #region Method

        /// <summary>
        /// 在出发CollectionChanged时不允许向集合中添加数据
        /// </summary>
        private void CheckReentrancy()
        {
            if (this._isBusy)
            {
                throw new InvalidOperationException("ItemCollection Can't Change during the OnItemsChanged");
            }
        }
        /// <summary>
        /// 更新数据源保持与集合中的数据源一致
        /// </summary>
        /// <param name="newItemsSource"></param>
        internal void UpdateItemsSourceList(IEnumerable newItemsSource)
        {
            if (_collectionChangedListener != null)
            {
                _collectionChangedListener.Disconnect();
                _collectionChangedListener = null;
            }
            if (newItemsSource == null)
            {
                this._itemsSource = null;
            }
            else
            {
                this._itemsSource = newItemsSource;
                InitializeSnapshot();
                this._collectionChangedListener = WeakCollectionChangedListener.CreateIfNecessary(newItemsSource, this);
            }
            //每一次重新设置之后listener刚初始化，是不会监听到Reset事件的.
            this.NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        /// <summary>
        /// 处理集合变化
        /// </summary>
        /// <param name="e"></param>
        private void HandleCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (e.NewStartingIndex == base.Count)
                    {
                        base.Add(e.NewItems[0]);
                        return;
                    }
                    base.Insert(e.NewStartingIndex, e.NewItems[0]);
                    return;
                case NotifyCollectionChangedAction.Remove:
                    base.RemoveAt(e.OldStartingIndex);
                    return;
                case NotifyCollectionChangedAction.Replace:
                    base[e.NewStartingIndex] = e.NewItems[0];
                    break;
                case NotifyCollectionChangedAction.Reset:
                    this.InitializeSnapshot();
                    break;
                case NotifyCollectionChangedAction.Move:
                    break;
                default:
                    return;

            }
        }

        /// <summary>
        /// 当集合被一次添加或者被重置时需要重新初始化一下
        /// 以形成一定的对应关系
        /// </summary>
        private void InitializeSnapshot()
        {
            base.Clear();
            IEnumerator enumerator = _itemsSource.GetEnumerator();
            try
            {
                 while (enumerator.MoveNext())
                {
                    object current = enumerator.Current;
                    base.Add(current);
                }
            }
            finally
            {
                IDisposable disposable = enumerator as IDisposable;
                disposable.Dispose();
            }
        }

        internal bool ItemsSourceActive()
        {
            return this._itemsSource != null;
        }
        #endregion

        #region EventHandler

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        private void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            this._isBusy = true;
            try
            {
                if (this.CollectionChanged != null)
                {
                    this.CollectionChanged.Invoke(this, e);
                }
            }
            finally
            {
                this._isBusy = false;
            }
        }

        #endregion

        #region ICollectionChangedListener Implements

        void ICollectionChangedListener.OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if ((e.NewItems != null && e.NewItems.Count != 1) || (e.OldItems != null && e.OldItems.Count != 1))
            {
                throw new NotSupportedException("");
            }
            this.HandleCollectionChanged(e);
            NotifyCollectionChanged(e);
        }

        #endregion

    }
}
